﻿using System;
using System.ComponentModel;
using System.Windows;

using GroupChallengeWP7.GroupChallengeSvc;
using GroupChallengeWP7.Models;

namespace GroupChallengeWP7
{
    public class MainViewModel : INotifyPropertyChanged
    {
        #region Private Members

        private bool _WaitForStatusReturn = false;
        private int _AvoidCountWithWaitForStatusReturn = 0;
        private string _lastNotifiedConnectionStatus;

        private Player _player;
        private Network _network;
        private GameState _gameState;

        #endregion                              // Private Members

        #region Constructor

        public MainViewModel(Player player, Network network, GameState gameState)
        {
            _player = player;
            _network = network;
            _gameState = gameState;

            _network.NetworkStatusChanged += OnNetworkStatusChanged;
            _gameState.GameStateChanged += OnGameStateChanged;
        }

        #endregion

        #region Properties

        public string HostServer
        {
            get { return _network.HostServer; }
            set { _network.HostServer = value; }
        }

        public bool InGame
        {
            get { return _gameState.InGame; }
        }

        public Game CurrentGame
        {
            get { return _gameState.CurrentGame; }
        }

        public Question CurrentQuestion
        {
            get { return _gameState.CurrentQuestion; }
        }

        public DateTime LastCheckTime
        {
            get { return _network.LastCheckTime; }
        }

        public DateTime LastChangeTime
        {
            get { return _network.LastChangeTime; }
        }

        public string LastConnectionStatus
        {
            get { return _network.LastConnectionStatus ?? (_gameState.InGame ? "Joined" : "Not joined"); }
        }

        public string NickName
        {
            get { return _player.NickName; }
            set
            {
                if (value != _player.NickName)
                {
                    _player.NickName = value;

                    RaisePropertyChanged("ValidNickName");
                    RaisePropertyChanged("PlayerTitle");
                    RaisePropertyChanged("PlayerScoreTitle");
                }
            }
        }

        public bool ValidNickName
        {
            get
            {
                // Return if the NickName is set indicating a valid Join game.
                return !string.IsNullOrEmpty(NickName);
            }
        }

        public string FullName
        {
            get { return _player.FullName; }
            set { _player.FullName = value; }
        }

        public int PlayerId
        {
            get { return _player.PlayerId; }
            set { _player.PlayerId = value; }
        }

        public int Score
        {
            get { return _gameState.Score; }
        }

        public int LastGameScore
        {
            get { return _gameState.LastGameScore; }
        }

        public string PlayerTitle
        {
            get
            {
                string ret = "Group Challenge";

                if (!string.IsNullOrEmpty(NickName))
                {
                    ret += " - " + NickName;
                }

                return ret;
            }
        }

        public string PlayerScoreTitle
        {
            get
            {
                string ret = string.Empty;

                if (_gameState.InGame)
                {
                    ret = "Score: " + Score.ToString();
                }

                return ret;
            }
        }

        #region NotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion                              // NotifyPropertyChanged

        #endregion                              // Properties

        #region Internal Methods

        void OnNetworkStatusChanged()
        {
            if (_network.LastConnectionStatus != null &&
                _network.LastConnectionStatus != _lastNotifiedConnectionStatus)
            {
                //  Returns repetitive error or a nickname
                if (!_network.LastConnectionStatus.ToLower().Contains("nickname"))
                    _lastNotifiedConnectionStatus = _network.LastConnectionStatus;

                MessageBox.Show(_network.LastConnectionStatus, "Connection Error", MessageBoxButton.OK);
            }

            RaisePropertyChanged("LastConnectionStatus");
            RaisePropertyChanged("LastCheckTime");
            RaisePropertyChanged("LastChangeTime");
        }

        private void OnGameStateChanged()
        {
            RaisePropertyChanged("InGame");
            RaisePropertyChanged("CurrentGame");
            RaisePropertyChanged("CurrentQuestion");
            RaisePropertyChanged("Score");
            RaisePropertyChanged("PlayerScoreTitle");
            RaisePropertyChanged("LastConnectionStatus");
            RaisePropertyChanged("LastGameScore");
        }

        // Retrieve game statistics and update.
        internal void UpdateGameStats()
        {
            if (!_gameState.InGame)
            {
                return;
            }

            // Return up to 5 times before possible duplicate status request.
            if (_AvoidCountWithWaitForStatusReturn > 5)
            {
                _AvoidCountWithWaitForStatusReturn = 0;
                _WaitForStatusReturn = false;
            }

            // Still getting the last request.
            if (_WaitForStatusReturn)
            {
                _AvoidCountWithWaitForStatusReturn++;

                return;
            }

            // Call server to return on callback to update state.
            _network.GetCurrentGameState();
        }

        #endregion                              // Internal Methods

        #region Service calls
        public void JoinGame()
        {
            if (!_gameState.InGame && !string.IsNullOrEmpty(_player.NickName))
            {
                _network.JoinGame(_player);
            }
        }

        public void LeaveGame()
        {
            if (_gameState.InGame)
            {
                MessageBoxResult res = MessageBox.Show("Leave the game?", "Confirm Leave", MessageBoxButton.OKCancel);
                if (res == MessageBoxResult.OK)
                {
                    _network.LeaveGame(_player);
                }
            }
        }

        public int Answer(int answerNumber, int lastQuesionAnswered)
        {
            // Only one vote per question.
            if (
                null != CurrentQuestion &&
                lastQuesionAnswered != CurrentQuestion.QuestionId &&
                answerNumber > 0)
            {
                lastQuesionAnswered = CurrentQuestion.QuestionId;

                _network.Answer(answerNumber, NickName, CurrentQuestion);
            }

            return lastQuesionAnswered;
        }
        #endregion
    }
}